package com.doc.service.impl;

import com.doc.entity.MyFileInfo;
import com.doc.service.ViewFile;
import com.doc.websocket.service.WebSocketServer;
import com.spire.doc.Document;
import com.spire.doc.documents.Paragraph;
import com.spire.doc.documents.TextSelection;
import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.general.find.PdfTextFind;
import com.spire.xls.CellRange;
import com.spire.xls.Workbook;
import com.spire.xls.Worksheet;
import com.spire.xls.collections.WorksheetsCollection;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class VileFileImpl implements ViewFile {
    //匹配上的文件
     int  count = 0;
    //遍历过的文件符合文件类型的文件
    int findFileCount = 0;
    //遍历过的文件
    int count1 = 0;

    private final WebSocketServer webSocketServer;

    /**
     * 构造注入
     * @param webSocketServer webSocket网络协议
     */
    public VileFileImpl(WebSocketServer webSocketServer) {
        this.webSocketServer = webSocketServer;
    }

    @Override
    public HashMap<String, Object> viewFile(MyFileInfo myFileInfo) throws Exception {
        long startTime = System.currentTimeMillis();   //获取开始时间


        System.out.println("======================开始搜索========================");
        count = 0;
        findFileCount = 0;
        count1 = 0;
        //总数据
        HashMap<String, Object> data = new HashMap<>();
        //文件数据
        List<MyFileInfo> myFileInfos = new ArrayList<>();
        //递归方法
        doGetFileList(myFileInfo.getFilePath(), myFileInfos, myFileInfo);
        data.put("fileListInfo", myFileInfos);
        data.put("fileCount", count);
        data.put("findFileCount", findFileCount);
        System.out.println("======================搜索完成========================");
        long endTime = System.currentTimeMillis(); //获取结束时间
        long runTime = ((endTime - startTime) / 1000);
        System.out.println("耗时：" + runTime + "秒");
        data.put("runTime", runTime);
        return data;
    }
    /**
     * 递归获取文件列表
     *
     * @param filePath 文件路径
     */
    public void doGetFileList(String filePath, List<MyFileInfo> myFileInfos, MyFileInfo myFileInfo) throws Exception {
        //增加遍历次数
        Date date = new Date();
        SimpleDateFormat spf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //创建file文件
        File file = new File(filePath);
        if (file.exists()) {
            if (file.isDirectory()) {
                //如果是文件夹继续进行递归
                String[] fileNames = file.list();
                if(fileNames==null){
                    return;
                }
                for (String fileName : fileNames) {
                    doGetFileList(filePath + File.separator + fileName, myFileInfos, myFileInfo);
                }
            } else {
                //如果是文件则输出
                if (count1> myFileInfo.getMaxFileCount()) {
                    throw new Exception("扫描文件数量过大");
                }
                count1++;
                String fileName = file.getName();
                String fileType = getFileType(fileName);
                String absolutePath = file.getAbsolutePath();
                //如果没有设置文件类型或者是用户搜索的类型      没有关键字不进行文档处理只列出目录
                if (myFileInfo.getFilterFileTypes() == null || myFileInfo.getFilterFileTypes().contains(fileType)) {
                    findFileCount++;
                    //System.out.println(spf.format(date) + " 文件搜索中(" + findFileCount + "|"+myFileInfo.getMayFindCount()+"):" + filePath);
                    MyFileInfo fileInfo = new MyFileInfo();
                    if (myFileInfo.getKeyWords() == null||myFileInfo.getKeyWords().size()==0) {
                        //设置文件名称
                        fileInfo.setFileNameHtml(fileName);
                        fileInfo.setFileName(fileName);
                        //设置文件路径
                        fileInfo.setFilePath(absolutePath);
                        //设置文件类型
                        fileInfo.setFileType(fileType);
                        myFileInfos.add(fileInfo);
                        count++;
                    } else {
                        doFindFile(myFileInfos, myFileInfo, fileType, absolutePath);
                    }
                }
            }
        }
    }

    /**
     * 处理文件
     *
     * @param myFileInfos 返回到前端的文件信息
     * @param fileInfo    前端输入的配置参数
     */
    public void doFindFile(List<MyFileInfo> myFileInfos, MyFileInfo fileInfo, String fileType, String filePath) throws IOException {
        long startTime = System.currentTimeMillis();   //获取开始时间
        if (".doc".equals(fileType) || ".docx".equals(fileType)) {
            doWord(myFileInfos, fileInfo, filePath);
        } else if (".pdf".equals(fileType)) {
            doPdf(myFileInfos, fileInfo, filePath);
        } else if (".xls".equals(fileType) || ".xlsx".equals(fileType)) {
            doExcel(myFileInfos, fileInfo, filePath);
        } else {
            System.out.println("未处理文件:" + filePath);
        }
        long endTime = System.currentTimeMillis(); //获取结束时间
        String runTime = (endTime - startTime) +"";
        webSocketServer.sendMessage(fileInfo.getUid(),(findFileCount*100)/fileInfo.getMayFindCount()+"##@@"+getFileName(filePath)+"**&&"+runTime);
    }

    /**
     * 处理excel文件
     *
     * @param myFileInfos 返回文件列表信息
     * @param fileInfo    前端入参
     * @param filePath    文件路径
     */
    private void doExcel(List<MyFileInfo> myFileInfos, MyFileInfo fileInfo, String filePath) {
        try {
            Workbook workbook = new Workbook();
            workbook.loadFromFile(filePath);
            //获取excel工作簿
            WorksheetsCollection worksheets = workbook.getWorksheets();
            //循环工作簿
            for (int i = 0; i < worksheets.size(); i++) {
                Worksheet worksheet = worksheets.get(i);
                //循环关键字
                for (String keyWord : fileInfo.getKeyWords()) {
                    //循环获取得到关键字段
                    CellRange[] allString = worksheet.findAllString(keyWord, false, false);
                    if (allString.length > 0) {
                        //匹配到关键字
                        count++;
                        MyFileInfo data = new MyFileInfo();
                        data.setKeyWord(keyWord);
                        data.setFileType(getFileType(filePath));
                        data.setFilePath(filePath);
                        data.setFileName(getFileName(filePath) + " ---- " + "工作簿（" + (i + 1) + "）" + worksheet.getName());
                        data.setFileNameHtml(getFileName(filePath) + setHeightLight("工作簿（" + (i + 1) + "）" + worksheet.getName(), "success"));
                        LinkedHashSet<String> content = new LinkedHashSet<>();
                        LinkedHashSet<String> contentHtml = new LinkedHashSet<>();
                        for (CellRange cellRange : allString) {
                            String matchString = cellRange.getRichText().getText();
                            content.add(matchString);
                            contentHtml.add(setKeyWordHeightLight(matchString, keyWord, "danger"));
                        }
                        data.setContent(content);
                        data.setContentHtml(contentHtml);
                        myFileInfos.add(data);
                    }
                }
            }
        } catch (Exception e) {
            System.out.println("处理excel异常：" + e.getMessage());
        }
    }

    /**
     * 处理pdf文件
     *
     * @param filePath 文件路径
     */
    private void doPdf(List<MyFileInfo> myFileInfos, MyFileInfo fileInfo, String filePath) {
        try {
            PdfDocument pdf = new PdfDocument(filePath);
            PdfTextFind[] result = null;
            for (String keyWord : fileInfo.getKeyWords()) {
                HashSet<String> content = new LinkedHashSet<>();
                boolean findKeyWord = false;
                LinkedHashSet<String> contentHtml = new LinkedHashSet<>();
                for (PdfPageBase page : (Iterable<PdfPageBase>) pdf.getPages()) {
                    PdfTextFind[] res = page.findText(keyWord).getFinds();
                    if (res.length > 0) {
                        findKeyWord = true;
                        for (PdfTextFind re : res) {
                            String lineText = re.getLineText();
                            content.add(lineText);
                            contentHtml.add(setKeyWordHeightLight(lineText, keyWord, "danger"));
                        }
                    }
                }
                if (findKeyWord) {
                    MyFileInfo data = new MyFileInfo();
                    data.setFileName(getFileName(filePath));
                    data.setFilePath(filePath);
                    data.setFileNameHtml(getFileName(filePath));
                    data.setFileType(getFileType(filePath));
                    data.setContentHtml(contentHtml);
                    data.setKeyWord(keyWord);
                    data.setContent(content);
                    myFileInfos.add(data);
                    count++;
                }
            }
        } catch (Exception exception) {
            System.out.println("处理pdf时异常！" + exception.getMessage());
        }

    }

    /**
     * 处理word文件
     *
     * @param filePath xx
     */
    public void doWord(List<MyFileInfo> myFileInfos, MyFileInfo fileInfo, String filePath) {
        try {
            Document document = new Document(filePath);
            for (String keyWord : fileInfo.getKeyWords()) {
                TextSelection[] allString = document.findAllString(keyWord, true, true);
                if (!(null == allString)) {
                    MyFileInfo data = new MyFileInfo();
                    data.setFileName(getFileName(filePath));
                    data.setFileNameHtml(getFileName(filePath));
                    data.setFilePath(filePath);
                    data.setFileType(getFileType(filePath));
                    data.setKeyWord(keyWord);
                    HashSet<String> content = new LinkedHashSet<>();
                    LinkedHashSet<String> contentHtml = new LinkedHashSet<>();
                    for (TextSelection textSelection : allString) {
                        Paragraph paragraph = (Paragraph) textSelection.getAsOneRange().getOwner();
                        content.add(paragraph.getText());
                        contentHtml.add(setKeyWordHeightLight(paragraph.getText(), keyWord, "danger"));
                    }
                    data.setContent(content);
                    data.setContentHtml(contentHtml);
                    myFileInfos.add(data);
                    count++;
                }
            }
        } catch (Exception exception) {
            System.out.println("处理word时异常！" + exception.getMessage());
        }
    }

    /**
     * 获取文件类型
     *
     * @param file 文件名称
     * @return 文件类型
     */
    private String getFileType(String file) {
        String fileType;
        if (file.contains(".")) {
            int i = file.lastIndexOf(".");
            fileType = file.substring(i);
        } else {
            fileType = "无文件类型";
        }
        return fileType.toLowerCase(Locale.ROOT);
    }

    /**
     * 获取文件名称
     *
     * @param filePath 文件路径
     * @return 文件名称
     */
    private String getFileName(String filePath) {
        String fileName;
        if (filePath.contains(File.separator)) {
            fileName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
        } else {
            fileName = filePath;
        }
        return fileName;
    }

    /**
     * 设置  设置匹配文本关键字高亮
     *
     * @param matchString 匹配到文本
     * @param keyWord     关键字
     * @param type        高亮类型 success danger info  warning
     * @return html 文本前端解析
     */
    private String setKeyWordHeightLight(String matchString, String keyWord, String type) {
        //计算匹配文本中包含多个 关键词
        int index = matchString.indexOf(keyWord);
        int i = 1;
        int j = 0;
        while (index >= 0) {
            j++;
            //逻辑处理
            //别纠结逻辑了可以实现行 垃圾代码
            if (j == i) {
                matchString = matchString.substring(0, index) + setHeightLight(keyWord, type) + matchString.substring(index + keyWord.length());
                i = 2;
                j = 0;
            }
            index = matchString.indexOf(keyWord, index + 1);
        }
        return matchString;
    }

    /**
     * 返回标签给前端 直接处理样式
     *
     * @param s    文本
     * @param type success danger info  warning
     * @return 得到不匹配到类型  直接返回原来参数
     */
    private String setHeightLight(String s, String type) {
        if ("success".equals(type) || "danger".equals(type) || "info".equals(type) || "warning".equals(type)) {
            s = "<span class='el-tag el-tag--" + type + " el-tag--small el-tag--light item' >" + s + "</span>";
        } else {
            s = "<span class='el-tag el-tag--info el-tag--small el-tag--light item' >" + s + "</span>";
        }
        return s;
    }
}
